#include "../../../socket/internal/IoPortService.h"
#include "../../../socket/TcpIoClient.h"
#include "../../../socket/TcpIoSocket.h"
#include "../../../socket/Timer.h"
#include "../../../log/LogFactory.h"
#include "../ClassFactory.h"
#include "ClientServer.h"
#include "MacroTools.h"
#include "Client.h"

DEF_BEG_LIBTOOLS

ClientServer::ClientServer() :_tcpClient(new CTcpIoClient())
{
	_isServer = false;
}

ClientServer::~ClientServer()
{

}

bool ClientServer::Init(const TcpConfig& c)
{
	*_config = c;

	return true;
}

bool ClientServer::Run()
{
	return _tcpClient->Run();
}

void ClientServer::NotifyExit()
{
	return _tcpClient->NotifyStop();
}

void ClientServer::SetClient(const SharedPtr<Client>& c)
{
	c->_service = this;
	c->_isClose = false;
	c->_cliSock.Reset(new CTcpIoSocket(_tcpClient.Get()));
	c->_timer.Reset(new CTimer(_tcpClient->GetTcpServicePtr()));
	if (this->_config->_timeout != 0) c->SetTimeout(CUnitTime(this->_config->_timeout));
	c->SetSocketOpt(c->_cliSock.Get());
	this->AddClient(c);
}

void ClientServer::PostConnect(void* invoker /* = NullPtr */, const char* addr /* = NullPtr */, DWORD port /* = 0 */)
{
	SharedPtr<Client> c(_config->_clientFactory->GetClient(), ReleaseClient(_config->_clientFactory.Get()));
	c->_invoker = invoker;
	SetClient(c);
	c->_cliSock->SetDomain(_config->_family);
	c->_cliSock->SetAddr(addr);
	c->_cliSock->SetPort(port);
	CSockError ec = _tcpClient->Init(*c->_cliSock);
	LOG_TOOLS(LOG_NORMAL) << "PostConnect client_id:" << c->GetClientIden();
	if (!ec){
		_tcpClient->AsyncConnect(*c->_cliSock, ClientServer::ConnectComplete, c.Get());
	}
	else
	{
		c->Post(&ClientServer::ConnectFailed, c.Get());
		LOG_TOOLS(LOG_ERROR) << "init socket failed:" << c.Get() << ", addr:" << addr << ", port:" << port << ", msg:" << ec.GetErrorMsg();
	}
}

void ClientServer::Post(DWORD(*complete)(void*), void* invoker)
{
	_tcpClient->Post(complete, invoker);
}

int ClientServer::DealConnect(Client* c, const char* msg, void* invoker)
{
	if (c){
		c->Start(invoker);
		c->Close();
	}

	return 0;
}

DWORD ClientServer::ConnectComplete(CSockError ec, void* invoker)
{
	Client* c = (Client*)invoker;
	DWORD ret = 0;

	if (ec)
	{
		LOG_TOOLS(LOG_ERROR) << "DealConnect error:" << ec.GetErrorMsg() << ", client_id:" << c->GetClientIden();
		ret = dynamic_cast<ClientServer*>(c->_service)->DealConnect(c, ec.GetErrorMsg().c_str(), c->_invoker);
		c->Close();
	}
	else{
		ret = dynamic_cast<ClientServer*>(c->_service)->DealConnect(c, NullPtr, c->_invoker);
	}

	return ret;
}

DWORD ClientServer::ConnectFailed(void* invoker)
{
	CSockError ec(CSockError::UNINIT);
	return ConnectComplete(ec, invoker);
}

CBasicService* ClientServer::GetTcpService() const
{
	return _tcpClient->GetTcpServicePtr();
}

DEF_END_LIBTOOLS